// Demo_Server.cpp : Defines the entry point for the console application.
//
#include "Demo_Server.h"

enum PacketID
{
	UCPID_NULL = ATMOS::API_USER,
	UCPID_SERVER,
	UCPID_CLIENT
};

// messages that flow upstream to the server
enum ClientPacketID
{
	CPID_NULL = 0,
	CPID_CHAT,
	CPID_DIGBUILD,
	CPID_SET_PLAYER_POS
};

// messages that flow downstream to the clients
enum ServerPacketID
{
	SPID_NULL = 0,
	SPID_CHAT,
	SPID_DIGBUILD,
	SPID_SET_PLAYER_POS
};


// DemoServer::GameServerListener
////////////////////////////////////////////////////////////////////////////////////////////////////
DemoServer::GameServerListener::GameServerListener( DemoServer *demoClient  ) :
mDemoServer( demoClient )
{
}

DemoServer::GameServerListener::~GameServerListener()
{
}

void DemoServer::GameServerListener::onAtmosPacket( ATMOS::Packet *packet )
{
	switch( packet->getAtmosPacketID() )
	{
	case ATMOS::API_REGISTER_CLIENT:
		mDemoServer->mClients.push_back( packet->getRakNetGUID() );
		break;
	case ATMOS::API_UNREGISTER_CLIENT:
		mDemoServer->mClients.erase( std::find( 
			mDemoServer->mClients.begin(), mDemoServer->mClients.end(), packet->getRakNetGUID() ) );
		break;
	case UCPID_SERVER:
		{
			std::cout << "UCPID_SERVER" << std::endl;
			
			unsigned char subpid = packet->readUChar();
			switch( subpid )
			{
			case SPID_CHAT:
				{
					std::cout << "SPID_CHAT" << std::endl;
					std::string message = packet->readString();
					/*
					for( GUIDList::iterator iter = mDemoServer->mClients.begin();
						iter != mDemoServer->mClients.end();
						++iter )
					{
						ATMOS::Packet p( (ATMOS::PacketID)UCPID_CLIENT, 
							mDemoServer->mServer.getLocalGUID() );
						p.writeUChar( CPID_CHAT );
						p.writeString( message );
						mDemoServer->mServer.sendAtmosPacket( &p, (*iter) );
					}*/
					
						ATMOS::Packet p( (ATMOS::PacketID)UCPID_CLIENT, 
							mDemoServer->mServer.getLocalGUID() );
						p.writeUChar( CPID_CHAT );
						p.writeString( message );
						mDemoServer->mServer.broadcastPacket( &p );
				}
				break;
			case SPID_SET_PLAYER_POS:
				{
					//std::cout << "SPID_SET_PLAYER_POS" << std::endl;
					
					float x = packet->readFloat();
					float y = packet->readFloat();
					float z = packet->readFloat();
					
					std::string message = packet->readString();
					for( GUIDList::iterator iter = mDemoServer->mClients.begin();
						iter != mDemoServer->mClients.end();
						++iter )
					{
						ATMOS::Packet p( (ATMOS::PacketID)UCPID_CLIENT, 
							mDemoServer->mServer.getLocalGUID() );
						p.writeUChar( CPID_SET_PLAYER_POS );
						p.writeFloat( x );
						p.writeFloat( y );
						p.writeFloat( z );
						mDemoServer->mServer.sendPacket( &p, (*iter) );
					}
				}
				break;
			}
		}
		break;
	case UCPID_CLIENT:
		{
			std::cout << "UCPID_CLIENT" << std::endl;			
		}
		break;
	}
}

void DemoServer::GameServerListener::onDisconnectionNotification( const std::string &senderGUID ) 
{
}

void DemoServer::GameServerListener::onAlreadyConnected( const std::string &senderGUID )
{
}

void DemoServer::GameServerListener::onIncompatibleProtocolVersion( const std::string &senderGUID )
{
}

void DemoServer::GameServerListener::onRemoteDisconnectionNotification( const std::string &senderGUID ) 
{
}

void DemoServer::GameServerListener::onRemoteConnectionLost( const std::string &senderGUID )
{
}

void DemoServer::GameServerListener::onNewIncomingConnection( const std::string &senderGUID ) 
{
	std::cout << "[GAME SERVER] new incoming connection: " << senderGUID << std::endl;
}

void DemoServer::GameServerListener::onConnectionBanned( const std::string &senderGUID )
{
}

void DemoServer::GameServerListener::onConnectionAttemptFailed( const std::string &senderGUID )
{
}

void DemoServer::GameServerListener::onNoFreeIncomingConnections( const std::string &senderGUID )
{
}

void DemoServer::GameServerListener::onInvalidPassword( const std::string &senderGUID )
{
}

void DemoServer::GameServerListener::onConnectionLost( const std::string &senderGUID ) 
{
}

void DemoServer::GameServerListener::onConnectionRequestAccepted( const std::string &senderGUID )
{
	std::cout << "[GAME SERVER] connection request accepted: " << senderGUID << std::endl;
}

void DemoServer::GameServerListener::onUnknownPacket( const std::string &senderGUID )
{
}

// DemoServer::GameServerListener
////////////////////////////////////////////////////////////////////////////////////////////////////
DemoServer::MSClientListener::MSClientListener( DemoServer *demoServer, const std::string &name ) :
mDemoServer( demoServer ),
mName( name )
{
}

DemoServer::MSClientListener::~MSClientListener()
{
}

void DemoServer::MSClientListener::onAtmosPacket( ATMOS::Packet *packet )
{
	switch( packet->getAtmosPacketID() )
	{
	case ATMOS::API_MASTER_SERVER:
		{
			ATMOS::PacketID mspid = (ATMOS::PacketID)packet->readUChar();
			switch( mspid )
			{
			case ATMOS::MSPID_CL_GAME_CONNECTION_APPROVED:
				std::cout << "[MSCLIENT] " << "connection with client approved by master server" << std::endl;
				break;
			case ATMOS::MSPID_CL_GAME_CONNECTION_DENIED:
				std::cout << "[MSCLIENT] " << "MSPID_CL_GAME_CONNECTION_DENIED" << std::endl;
				break;
			}
		}
	case ATMOS::API_DEBUG_1:
		std::cout << "***ERROR GOT CLIENT CHAT: " << packet->readString() << std::endl;
		break;
	case ATMOS::API_DEBUG_2:
		std::cout << "SERVER CHAT: " << packet->readString() << std::endl;
		break;
	}
}

void DemoServer::MSClientListener::onDisconnectionNotification( const std::string &senderGUID )
{
}

void DemoServer::MSClientListener::onAlreadyConnected( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onIncompatibleProtocolVersion( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onRemoteDisconnectionNotification( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onRemoteConnectionLost( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onNewIncomingConnection( const std::string &senderGUID ) 
{
	std::cout << "[MSCLIENT] " << "new incoming connection: " << senderGUID << std::endl;
}

void DemoServer::MSClientListener::onConnectionBanned( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onConnectionAttemptFailed( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onNoFreeIncomingConnections( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onInvalidPassword( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onConnectionLost( const std::string &senderGUID ) 
{
}

void DemoServer::MSClientListener::onConnectionRequestAccepted( const std::string &senderGUID )
{
	mDemoServer->mMSServerGUID = senderGUID;
	std::cout << "[MSCLIENT] " << "connection request accepted: " << senderGUID << std::endl;
}

void DemoServer::MSClientListener::onUnknownPacket( const std::string &senderGUID ) 
{
}

// DemoServer
////////////////////////////////////////////////////////////////////////////////////////////////////
DemoServer::DemoServer( const std::string &name, 
	const ATMOS::NetworkConnectionInfo &masterServerInfo,
	const ATMOS::NetworkConnectionInfo &serverInfo ) :
mLogManager( 0 ),
mMSClient( 0 ),
mServerInitialized( false ),
mGameServerListener( 0 ),
mMSClientListener( 0 )
{
	mLogManager = 
			new ATMOS::LogManager( 
#ifndef _DEBUG
			"Demo_Server.debug.log.txt"
#else
			"Demo_Server.log.txt"
#endif
			);
	
	initializeConnectionToMasterServer( name, masterServerInfo, serverInfo.serverPort );
	initializeGameServerConnection( serverInfo );
}

void DemoServer::initializeConnectionToMasterServer( const std::string &name,
	const ATMOS::NetworkConnectionInfo &masterServerInfo, int localGamePort )
{
	std::cout << "*********************" << std::endl;
	std::cout << "master server information" << std::endl;
	std::cout	<< "name: " << name << std::endl
				<< "server port: " << masterServerInfo.serverPort << std::endl
				<< "server ip: " << masterServerInfo.serverIP << std::endl
				<< "client port: " << masterServerInfo.clientPort << std::endl
				<< "max connections: " << masterServerInfo.maxConnections << std::endl;
	std::cout << "*********************" << std::endl;

	mMSClient = new ATMOS::MSClient( true, name, masterServerInfo, localGamePort );
	mMSClientListener = new MSClientListener( this, name );
	mMSClient->getNetworkManager()->addPacketListener( mMSClientListener );
	
	bool connected = false;
	for( int i = 0; i < 10 && !connected; ++i )
	{
		connected = mMSClient->connectedToMasterServer();
		Sleep( 200 );
	}

	if( !connected )
	{
		throw std::runtime_error( "unable to connect to master server" );
	}
}

void DemoServer::shutdownConnectionToMasterServer()
{
	if( mMSClient )
	{
		mMSClient->getNetworkManager()->removePacketListener( mMSClientListener );
		delete mMSClientListener;
		mMSClientListener = 0;
		delete mMSClient;
		mMSClient = 0;
	}
}

void DemoServer::initializeGameServerConnection( 
	const ATMOS::NetworkConnectionInfo &serverInfo )
{
	ATMOS_ASSERT( !mServerInitialized );
	mServer.initialize( serverInfo );
	
	mGameServerListener = new GameServerListener( this );
	mServer.addPacketListener( mGameServerListener );

	mServerInitialized = true;
}

void DemoServer::shutdownGameServerConnection()
{
	if( mServerInitialized )
	{
		if( mGameServerListener )
		{
			mServer.removePacketListener( mGameServerListener );
			delete mGameServerListener;
		}

		mServer.shutdown();
		mServerInitialized = false;
	}
}

DemoServer::~DemoServer()
{
	shutdownGameServerConnection();

	shutdownConnectionToMasterServer();
	delete mLogManager;
}

void DemoServer::update()
{
	if( mServerInitialized ) 
		mServer.update();

	mMSClient->update();
}

void DemoServer::listClients()
{
	for( GUIDList::iterator iter = mClients.begin(); iter != mClients.end(); ++iter )
	{
		std::cout << "client: " << (*iter) << std::endl;
	}
}

std::string DemoServer::getGameLocalGUID() const
{
	return mServer.getLocalGUID();
}

std::string DemoServer::getMSLocalGUID() const
{
	return mMSClient->getNetworkManager()->getLocalGUID();
}

std::string DemoServer::getMSServerGUID() const
{
	return mMSServerGUID;
}

void getConnectionInfoFromUser( bool masterServer, ATMOS::NetworkConnectionInfo &info );

int _tmain(int argc, _TCHAR* argv[])
{	
	try
	{		
		std::string serverName;
		ATMOS::NetworkConnectionInfo masterServerInfo;
		ATMOS::NetworkConnectionInfo serverInfo;

		std::cout	<< "(1) do auto test A" << std::endl 
					<< "(2) do auto test B" << std::endl 
					<< "(3) do manual test" << std::endl;

		char c = 0;
		bool done = false;
		while( !_kbhit() && !done )
		{
			c = _getch();
			switch( c )
			{
			case '1':
				serverName = "server_A";

				masterServerInfo.serverPort = 6677;
				//masterServerInfo.serverIP = "76.11.215.58";
				//masterServerInfo.serverIP = "184.106.161.158";
				masterServerInfo.serverIP = "127.0.0.1";
				masterServerInfo.clientPort = 7788;
				masterServerInfo.maxConnections = 32;

				serverInfo.serverPort = 1050;
				serverInfo.serverIP = "127.0.0.1";
				serverInfo.clientPort = 1051;
				serverInfo.maxConnections = 32;
				done = true;
				break;
			case '2':
				serverName = "server_B";

				masterServerInfo.serverPort = 6677;
				//masterServerInfo.serverIP = "76.11.215.58";
				masterServerInfo.serverIP = "184.106.161.158";
				masterServerInfo.clientPort = 7789;
				masterServerInfo.maxConnections = 32;

				serverInfo.serverPort = 7052;
				serverInfo.serverIP = "127.0.0.1";
				serverInfo.clientPort = 7053;
				serverInfo.maxConnections = 32;
				done = true;
				break;
			case '3':
				{
					char buffer[100];
					memset( buffer, '\0', 100 );
	
					std::cout << "name: ";
					if( gets_s( buffer, 100 ) )
					{
						serverName = buffer;
						if( serverName.empty() )
						{
							serverName = "default_server_name";
						}
					}
				}

				getConnectionInfoFromUser( true, masterServerInfo );
				getConnectionInfoFromUser( false, serverInfo );
				done = true;
				break;
				break;
			default:
				break;
			}
		}

		masterServerInfo.connectionPassword = "test";
		masterServerInfo.maxConnections = 1000;
		masterServerInfo.occasionalPing = true;
		masterServerInfo.unreliableTimeout = 10000;
		masterServerInfo.shutdownTime = 500;

		DemoServer demoServer( serverName, masterServerInfo, serverInfo );

		bool loop = true;
		c = 0;
		while( loop )
		{
			demoServer.update();

			if( _kbhit() )
			{
				c = _getch();
				switch( c )
				{
				case 'g':
					std::cout 
						<< "game local GUID: " << demoServer.getGameLocalGUID() << std::endl
						<< "MS local GUID: " << demoServer.getMSLocalGUID() << std::endl
						<< "MS server GUID: " << demoServer.getMSServerGUID() << std::endl;
					break;
				case 'l':
					demoServer.listClients();
					break;
				case 't':
					std::cout << "still alive" << std::endl;
					break;
				case 'q': loop = false; break;
				}
			}
		}
	}
	catch( std::exception &error )
	{
		std::cerr << error.what() << std::endl;
		//ATMOS_LOG("error: " << error.what());
	}
	catch( ... )
	{
		std::cerr << "unknown exception" << std::endl;
		//ATMOS_LOG("error: unknown exception");
	}

	std::cout << "[press any key]" << std::endl;
	while( !_kbhit() );

	return 0;
}

void getConnectionInfoFromUser( bool masterServer, ATMOS::NetworkConnectionInfo &info )
{
	char buffer[100];
	memset( buffer, '\0', 100 );

	std::cout << (masterServer ? "master server " : "server ") << " IP: ";
	if( gets_s( buffer, 100 ) )
	{
		info.serverIP = buffer;
		if( info.serverIP.empty() )
		{
			// "184.106.161.158"; // windows server
			// "76.11.215.58"; // home IP
			info.serverIP = "127.0.0.1";
		}
	}
		
	std::cout << (masterServer ? "master server " : "server ") << " server port: ";
	if( gets_s( buffer, 100 ) )
	{
		std::string serverPort = buffer;
		if( serverPort.empty() )
		{			
			info.serverPort = masterServer ? 6677 : 1050;
		}
		else
		{
			info.serverPort = atoi( serverPort.c_str() );
		}
	}

	std::cout << (masterServer ? "master server " : "server ") << " client port: ";
	if( gets_s( buffer, 100 ) )
	{
		std::string clientPort = buffer;
		if( clientPort.empty() )
		{
			info.clientPort = masterServer ? 6688 : 1051;
		}
		else
		{
			info.clientPort = atoi( clientPort.c_str() );
		}
	}
}